﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Networking.NetworkSystem;

public class MyNetworkManager : NetworkManager
{
    [SerializeField] GameObject lobbyPlayerPfb;

    Dictionary<int, LobbyPlayer> lobbyPlayerDic = new Dictionary<int, LobbyPlayer>();
    public int LobbyPlayerCount { get => lobbyPlayerDic.Count; }
    public override void OnClientConnect(NetworkConnection conn)
    {
        base.OnClientConnect(conn);

        var lbyMsg = new LobbySpawnMsg();
        lbyMsg.nickName = Lobby.Instance.NickName;
        conn.Send(MyMsgType.NickName, lbyMsg);
        Lobby.Instance.OpenRoomWindow();
    }
    public override void OnClientDisconnect(NetworkConnection conn) {
        base.OnClientDisconnect(conn);
        Lobby.Instance.BackToLobby();
    }
    public override void OnServerSceneChanged(string sceneName) {
        base.OnServerSceneChanged(sceneName);
        Debug.Log("OnServerSceneChanged");
    }
    public override void OnClientSceneChanged(NetworkConnection conn) {
        // base.OnClientSceneChanged(conn);
        Debug.Log("OnClientSceneChanged");
        ClientScene.Ready(conn);
        // 告诉服务器，客户端的游戏状态为“已进入游戏”
        // 告诉服务器，创建俄罗斯方块实例
        client.Send(MyMsgType.Ready, new IntegerMessage(GameStateMsgType.START));
    }

    //public override void OnServerConnect(NetworkConnection conn) {
    //    base.OnServerConnect(conn);
    //}
    public override void OnStopHost() {
        base.OnStopHost();
        lobbyPlayerDic.Clear();
    }
    public override void OnServerDisconnect(NetworkConnection conn) {
        NetworkServer.DestroyPlayersForConnection(conn);
        lobbyPlayerDic.Remove(conn.connectionId);
    }
    public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
    {
        // 向所有已存在的玩家发送新玩家的 connId 和 nickName
        // 向新玩家发送已存在玩家的 connId 和 nickName
        // https://docs.unity3d.com/cn/current/Manual/class-NetworkConnection.html

        // Create LobbyPlayer
        GameObject go;
        Transform startPos = GetStartPosition();
        if (startPos != null) {
            go = (GameObject)Instantiate(lobbyPlayerPfb, startPos.position, startPos.rotation);
        } else {
            go = (GameObject)Instantiate(lobbyPlayerPfb, Vector3.zero, Quaternion.identity);
        }

        // Register Handler to get nickname
        var lbyPlayer = go.GetComponent<LobbyPlayer>();
        if (!lobbyPlayerDic.ContainsKey(conn.connectionId)) {
            lobbyPlayerDic.Add(conn.connectionId, lbyPlayer);
            conn.RegisterHandler(MyMsgType.NickName, OnReceiveNickname);
            conn.RegisterHandler(MyMsgType.Ready, OnClientReady);
        }

        NetworkServer.AddPlayerForConnection(conn, go, playerControllerId);
    }

    #region SelfMsgHandler
    public void OnReceiveNickname(NetworkMessage msg_) {
        var lbyMsg = msg_.ReadMessage<LobbySpawnMsg>();
        // refresh all player's nickname
        foreach (var player in lobbyPlayerDic) {
            if (player.Key == msg_.conn.connectionId) {
                player.Value.nickName = lbyMsg.nickName;
            }
            player.Value.SetDirtyBit(1);
        }
        Lobby.Instance.RefreshLobbyStartBtn();
    }
    public void OnClientReady(NetworkMessage msg_) {
        var intMsg = msg_.ReadMessage<IntegerMessage>();
        if (GameStateMsgType.START == intMsg.value) {
            // GameState.Start 代表游戏已切换到 MultiGame 场景
            // 此时，我们需要创建 PlayerPfb，并检测是否所有的玩家都已进入 Start 状态
            // 如果所有玩家都进入了 Start 状态，则进行开始倒计时。
            // 当计时结束时，游戏开始
            Debug.Log($"{msg_.conn.connectionId} 进入到了游戏场景");
        }
        else { 
            // GameState.Ready & GameState.NotReady 是 Lobby 大厅内的行为
            foreach (var player in lobbyPlayerDic) {
                if (player.Key == msg_.conn.connectionId) {
                    player.Value.gameState = intMsg.value;
                }
                player.Value.SetDirtyBit(1);
            }
            Lobby.Instance.RefreshLobbyStartBtn();
        }
    }
    #endregion

    #region LobbyTools
    public bool CheckIsAllClientGetReadyInLobby() {
        // Check is all client ready to start, and notice Lobby.
        bool isAllClientReady = true;
        foreach (var player in lobbyPlayerDic) {
            if (GameStateMsgType.NOT_READY == player.Value.gameState && !player.Value.isLocalPlayer) {
                isAllClientReady = false;
                break;
            }
        }
        return isAllClientReady;
    }
    #endregion
}
